#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

enum ERROR
{
    USAGE_ERR = 1,
    SOCKET_ERR
};
enum class Status // C++11 强类型枚举
{
    NEW,          // 新建状态，就是单纯的连接
    CONNECTING,   // 正在连接，仅仅方便查询conn状态
    CONNECTED,    // 连接或者重连成功
    DISCONNECTED, // 重连失败
    CLOSED        // 连接失败，经历重连，无法连接
};
static const int DefaultSocked = -1;
static const int retry_interval = 1;
static const int retey_MaxConnection = 5;
// 客户端连接业务处理类
class ClientConnection
{
public:
    ClientConnection(const string &serverip, uint16_t serverport)
        : _socked(DefaultSocked),
          _status(Status::NEW),
          _retry_interval(retry_interval),
          _retey_MaxConnection(retey_MaxConnection),
          _serverport(serverport),
          _serverip(serverip) {}
    Status GetStatus()
    {
        return _status;
    }
    void Connection()
    {
        _socked = socket(AF_INET, SOCK_STREAM, 0);
        if (_socked < 0)
        {
            cerr << "socket创建失败!" << endl;
            exit(ERROR::SOCKET_ERR);
        }
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverport);
        inet_pton(AF_INET, _serverip.c_str(), &server.sin_addr);
        int n = connect(_socked, (struct sockaddr *)&server, sizeof(server));
        if (n < 0)
        {
            Disconnection();
            _status = Status::DISCONNECTED;
            return;
        }
        _status = Status::CONNECTED; // 连接成功
    }
    void Process()
    {
        string message = "hello server";
        while (true)
        {
            char buffer[1024];
            ssize_t n = write(_socked, message.c_str(), message.size());
            if (n > 0)
            {

                ssize_t m = read(_socked, buffer, sizeof(buffer) - 1);

                if (m > 0)
                {
                    buffer[n] = 0;
                    cout << "echo messsge -> " << buffer << endl;
                }
                else if (m == 0)
                {
                    _status = Status::DISCONNECTED;
                    break;
                }
                else
                {
                    std::cout << "read m : " << m << "errno: " << errno << "errno string: " << strerror(errno) << std::endl;
                    _status = Status::CLOSED;
                    break;
                }
            }
            else
            {
                std::cout << "write n : " << n << "errno: " << errno << "errno string: " << strerror(errno) << std::endl;
                _status = Status::CLOSED;
                break;
            }
            sleep(1);
        }
    }
    void Reconnection()
    {
        _status = Status::DISCONNECTED; // 正在重连
        int cnt = 0;
        while (true)
        {
            cnt++;
            Connection();
            if (_status == Status::CONNECTED)
            {
                return;
            }
            if (cnt > retey_MaxConnection)
            {
                _status = Status::CLOSED;
                break;
            }
            std::cout << "重连次数: " << cnt << std::endl;
            sleep(_retry_interval);
        }
    }
    void Disconnection()
    {
        if (_socked != DefaultSocked)
        {
            close(_socked);
            _socked = DefaultSocked;
            _status = Status::CLOSED;
        }
    }
    ~ClientConnection() {}

private:
    int _socked;
    Status _status;
    int _retry_interval;      // 重连时间间隔
    int _retey_MaxConnection; // 最大重连次数
    uint16_t _serverport;
    string _serverip;
};

class TcpClient
{
public:
    TcpClient(const string &serverip, uint16_t serverport) : _con(serverip, serverport)
    {
    }
    void Execute()
    {
        while (true)
        {
            switch (_con.GetStatus())
            {
            case Status::NEW:
                _con.Connection();
                break;
            case Status::CONNECTED:
                std::cout << "连接成功, 开始进行通信." << std::endl;
                _con.Process();
                break;
            case Status::DISCONNECTED:
                _con.Reconnection();
                std::cout << "重连失败, 退出." << std::endl;
                break;
            case Status::CLOSED:
                _con.Disconnection();
                return;
            default:
                break;
            }
        }
    }
    ~TcpClient() {}

private:
    ClientConnection _con;
};
void Usage(const string &process)
{
    std::cout << "\n\rUsage: " << process << " prot[1024]+\n"
              << " serverip\n"
              << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(ERROR::USAGE_ERR);
    }
    uint16_t serverport = stoi(argv[2]);
    string serverip = argv[1];
    TcpClient tcpclient(serverip, serverport);
    tcpclient.Execute();
    return 0;
}